using AdminApiTemplate.Common.Exceptions;
using AdminApiTemplate.Common.Helpers;
using AdminApiTemplate.Services.AdminUser;
using AdminApiTemplate.Services.AdminUser.Models;
using AdminApiTemplate.Services.WorkWx;
using AdminApiTemplate.ThirdParty.Redis;

namespace AdminApiTemplate.Aggregates.Login
{
    /// <summary>
    /// 登录管理
    /// </summary>
    public class LoginComposite
    {
        private readonly AdminUserService _adminUserService;

        private readonly WorkWxService _workWxService;

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="adminUserService"></param>
        /// <param name="workWxService"></param>
        public LoginComposite(
            AdminUserService adminUserService,
            WorkWxService workWxService)
        {
            _adminUserService=adminUserService;
            _workWxService =workWxService;
        }

        /// <summary>
        /// 账号密码登录
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        public async Task<string> ByPassAsync(ByPassRequestModel request)
        {
            var user = await _adminUserService.GetUserByNameAsync(request.UserName);
            if (user == null)
            {
                await _adminUserService.AddLoginLogAsync(new AddLoginLogRequest
                {
                    LogType = LogTypeEnum.Password,
                    UserName=request.UserName,
                    UserPass=request.UserPass,
                    Success=false,
                    Remark="账号或密码错误"
                });
                throw new WithCodeException((int)ErrorCodeEnum.InvalidArguments, "账号或密码错误");
            }

            var password = $"{request.UserPass}{user.PassSalt}";
            password = SecurityHelper.GetMD5String(password);
            password = SecurityHelper.GetSHA1String(password);

            if (password!=user.UserPass)
            {
                await _adminUserService.AddLoginLogAsync(new AddLoginLogRequest
                {
                    LogType = LogTypeEnum.Password,
                    UserName=request.UserName,
                    UserPass=request.UserPass,
                    Success=false,
                    Remark="账号或密码错误"
                });
                throw new WithCodeException((int)ErrorCodeEnum.InvalidArguments, "账号或密码错误");
            }

            var sk = await GetSKByUserAsync(user);
            await _adminUserService.AddLoginLogAsync(new AddLoginLogRequest
            {
                LogType = LogTypeEnum.Password,
                UserName=user.UserName,
                Success=true,
                Remark="登录成功"
            });
            return sk;
        }

        /// <summary>
        /// 企业微信扫码登录
        /// </summary>
        /// <param name="request"></param>
        /// <param name="corpId"></param>
        /// <param name="corpSecret"></param>
        /// <returns></returns>
        public async Task<string> ByWorkWxAsync(ByWorkWxRequestModel request, string corpId, string corpSecret)
        {
            var token = await _workWxService.GetAccessTokenAsync(corpId);
            if (string.IsNullOrEmpty(token))
            {
                var tokenResponse = await new ThirdParty.WorkWx.WorkWxApiProxy(corpId, corpSecret).RealGetAccessTokenAsync();
                if (tokenResponse != null)
                {
                    token=tokenResponse.access_token;
                    await _workWxService.UpdateAccessTokenAsync(corpId, token, DateTime.Now.AddSeconds(tokenResponse.expires_in));
                }
            }

            if (string.IsNullOrEmpty(token))
            {
                throw new WithCodeException((int)ErrorCodeEnum.Unknown, "登录失败，获取企业微信token失败");
            }

            var workWxUser = await new ThirdParty.WorkWx.WorkWxApiProxy(corpId, corpSecret).RealGetUserInfoAsync(token, request.Code);
            if (workWxUser==null || string.IsNullOrEmpty(workWxUser.UserId))
            {
                throw new WithCodeException((int)ErrorCodeEnum.Unknown, "登录失败，获取企业微信用户信息失败");
            }

            var user = await _adminUserService.GetUserByWorkWxAsync(workWxUser.UserId);
            if (user == null)
            {
                await _adminUserService.AddLoginLogAsync(new AddLoginLogRequest
                {
                    LogType = LogTypeEnum.WorkWx,
                    WorkWx=workWxUser.UserId,
                    Success=false,
                    Remark="登录失败，还未开通此企业微信登录权限，请联系管理员"
                });
                throw new WithCodeException((int)ErrorCodeEnum.InvalidArguments, "登录失败，还未开通此企业微信登录权限，请联系管理员");
            }

            var sk = await GetSKByUserAsync(user);
            await _adminUserService.AddLoginLogAsync(new AddLoginLogRequest
            {
                LogType = LogTypeEnum.WorkWx,
                WorkWx=workWxUser.UserId,
                Success=true,
                Remark="登录成功"
            });
            return sk;
        }

        /// <summary>
        /// 获取AdminUser的Token
        /// </summary>
        /// <param name="user"></param>
        /// <returns></returns>
        private async Task<string> GetSKByUserAsync(AdminUserDto user)
        {
            if (user.IsDisabled.GetValueOrDefault())
            {
                await _adminUserService.AddLoginLogAsync(new AddLoginLogRequest
                {
                    LogType = LogTypeEnum.Password,
                    UserName=user.UserName,
                    Success=false,
                    Remark="账号已禁用，无法登录"
                });
                throw new WithCodeException((int)ErrorCodeEnum.NotAllowed, "账号已禁用，无法登录");
            }

            await CreateUserCacheAsync(user);

            var sk = EncryptHelper.DESEncrypt($"{RandomHelper.RequestId()}{user.Id.GetValueOrDefault()}", "1qaz2WSX");
            sk = SKHelper.Create(sk);
            return sk;
        }

        /// <summary>
        /// 创建AdminUser的缓存
        /// </summary>
        /// <param name="user"></param>
        /// <returns></returns>
        private async Task CreateUserCacheAsync(AdminUserDto user)
        {
            var permissions = await _adminUserService.GetUserPermissionAllAsync(user.Id.GetValueOrDefault());
            if (!permissions.Any())
            {
                throw new WithCodeException((int)ErrorCodeEnum.InvalidArguments, "还未配置权限，请联系管理员");
            }

            var menuTree = await _adminUserService.GetPermissionTreeAsync(new GetPermissionTreeRequestModel(), user.Id.GetValueOrDefault());
            var cachedAdminUser = new CachedAdminUserDto
            {
                AUID = user.Id.GetValueOrDefault(),
                ChineseName = user.ChineseName,
                EnglishName = user.EnglishName,
                UserType = user.UserType,
                WorkWx = user.WorkWx
            };

            var userMenuTree = new List<MenuItem>();
            foreach (var item in menuTree)
            {
                var menu = new MenuItem
                {
                    Children=new List<MenuItem>(),
                    Code=item.code,
                    DisplayText=item.title,
                    Icon=null,
                    Id=item.id.GetValueOrDefault().ToString(),
                    Url=item.url
                };

                if (item.children!=null && item.children.Count>0)
                {
                    foreach (var child in item.children)
                    {
                        BuildMenuTree(permissions, menu, child);
                    }

                    if (menu.Children!=null && menu.Children.Count>0)
                    {
                        userMenuTree.Add(menu);
                    }
                }
                else
                {
                    var p = permissions.Where(w => w.Id==item.id).FirstOrDefault();
                    if (p!=null)
                    {
                        userMenuTree.Add(menu);
                    }
                }
            }

            cachedAdminUser.Menus = userMenuTree;
            cachedAdminUser.Permissions= permissions.Select(o => o.PermissionCode).ToList();
            var id = $"admin:{user.Id.GetValueOrDefault()}";
            RedisHelper.Set(id, cachedAdminUser, TimeSpan.FromHours(4));
        }

        /// <summary>
        /// 构建菜单树
        /// </summary>
        /// <param name="permissions"></param>
        /// <param name="menu"></param>
        /// <param name="item"></param>
        private void BuildMenuTree(IEnumerable<PermissionDto> permissions, MenuItem menu, GetPermissionTreeResponseModel item)
        {
            var childMenu = new MenuItem
            {
                Children=new List<MenuItem>(),
                Code=item.code,
                DisplayText=item.title,
                Icon=null,
                Id=item.id.GetValueOrDefault().ToString(),
                Url=item.url
            };

            if (item.children!=null && item.children.Count>0)
            {
                foreach (var child in item.children)
                {
                    BuildMenuTree(permissions, childMenu, child);
                }

                if (childMenu.Children!=null && childMenu.Children.Count>0)
                {
                    menu.Children.Add(childMenu);
                }
            }
            else
            {
                var p = permissions.Where(w => w.Id==item.id).FirstOrDefault();
                if (p!=null)
                {
                    menu.Children.Add(childMenu);
                }
            }
        }

        /// <summary>
        /// 绑定企业微信
        /// </summary>
        /// <param name="request"></param>
        /// <param name="corpId"></param>
        /// <param name="corpSecret"></param>
        /// <param name="AUID"></param>
        /// <returns></returns>
        public async Task<string> BindWorkWxAsync(ByWorkWxRequestModel request, string corpId, string corpSecret, long AUID)
        {
            var token = await _workWxService.GetAccessTokenAsync(corpId);
            if (string.IsNullOrEmpty(token))
            {
                var tokenResponse = await new ThirdParty.WorkWx.WorkWxApiProxy(corpId, corpSecret).RealGetAccessTokenAsync();
                if (tokenResponse != null)
                {
                    token=tokenResponse.access_token;
                    await _workWxService.UpdateAccessTokenAsync(corpId, token, DateTime.Now.AddSeconds(tokenResponse.expires_in));
                }
            }

            if (string.IsNullOrEmpty(token))
            {
                throw new WithCodeException((int)ErrorCodeEnum.Unknown, "绑定失败，获取企业微信token失败");
            }

            var workWxUser = await new ThirdParty.WorkWx.WorkWxApiProxy(corpId, corpSecret).RealGetUserInfoAsync(token, request.Code);
            if (workWxUser==null || string.IsNullOrEmpty(workWxUser.UserId))
            {
                throw new WithCodeException((int)ErrorCodeEnum.Unknown, "绑定失败，获取企业微信用户信息失败");
            }

            var user = await _adminUserService.GetUserByWorkWxAsync(workWxUser.UserId);
            if (user != null)
            {
                throw new WithCodeException((int)ErrorCodeEnum.Unknown, "绑定失败，此企业微信已绑定其他账号");
            }

            await _adminUserService.BindUserWorkWxAsync(workWxUser.UserId, AUID);
            var id = $"admin:{AUID}";
            var adminUser = RedisHelper.Get<CachedAdminUserDto>(id);
            adminUser.WorkWx = workWxUser.UserId;

            RedisHelper.Set(id, adminUser, TimeSpan.FromHours(4));
            return "绑定成功";
        }
    }
}
